home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / MOR55SRC.ZIP / MORIA / SOURCE / DEATH.C < prev    next >
C/C++ Source or Header  |  1992-12-07  |  24KB  |  944 lines

  1. /* source/death.c: code executed when player dies
  2.  
  3.    Copyright (c) 1989-92 James E. Wilson, Robert A. Koeneke
  4.  
  5.    This software may be copied and distributed for educational, research, and
  6.    not for profit purposes provided that this copyright and statement are
  7.    included in all such copies. */
  8.  
  9. /* Must read this before externs.h, as some global declarations use FILE. */
  10. #include <stdio.h>
  11.  
  12. #ifndef STDIO_LOADED
  13. #define STDIO_LOADED
  14. #endif
  15.  
  16. #include "config.h"
  17. #include "constant.h"
  18. #include "types.h"
  19.  
  20. #ifdef Pyramid
  21. #include <sys/time.h>
  22. #else
  23. #include <time.h>
  24. #endif
  25.  
  26. #include <ctype.h>
  27.  
  28. #ifndef USG
  29. /* only needed for Berkeley UNIX */
  30. #include <sys/param.h>
  31. #include <sys/types.h>
  32. #include <sys/file.h>
  33. #endif
  34.  
  35. #ifdef MSDOS
  36. #include <io.h>
  37. #else
  38. #if !defined(ATARIST_MWC) && !defined(MAC) && !defined(AMIGA)
  39. #if !defined(ATARIST_TC)
  40. #ifndef VMS
  41. #include <pwd.h>
  42. #else
  43. #include <file.h>
  44. #endif
  45. #endif
  46. #endif
  47. #endif
  48.  
  49. #ifdef VMS
  50. unsigned int getuid(), getgid();
  51. #else
  52. #ifdef unix
  53. #ifdef USG
  54. unsigned short getuid(), getgid();
  55. #else
  56. #ifndef SECURE
  57. #ifdef BSD4_3
  58. uid_t getuid(), getgid();
  59. #else  /* other BSD versions */
  60. int getuid(), getgid();
  61. #endif
  62. #endif
  63. #endif
  64. #endif
  65. #endif
  66.  
  67. #ifdef USG
  68. #ifndef ATARIST_MWC
  69. #include <string.h>
  70. #ifndef VMS
  71. #ifndef ATARIST_TC
  72. #include <fcntl.h>
  73. #endif
  74. #endif
  75. #endif
  76. #else
  77. #include <strings.h>
  78. #endif
  79.  
  80. /* This must be included after fcntl.h, which has a prototype for `open'
  81.    on some systems.  Otherwise, the `open' prototype conflicts with the
  82.    `topen' declaration.  */
  83. #include "externs.h"
  84.  
  85. #ifndef BSD4_3
  86. #ifndef ATARIST_TC
  87. long lseek();
  88. #endif /* ATARTIST_TC */
  89. #else
  90. off_t lseek();
  91. #endif
  92.  
  93. #if defined(USG) || defined(VMS) || defined(atarist)
  94. #ifndef L_SET
  95. #define L_SET 0
  96. #endif
  97. #ifndef L_INCR
  98. #define L_INCR 1
  99. #endif
  100. #endif
  101.  
  102. #ifndef VMS
  103. #ifndef MAC
  104. #if defined(ultrix) || defined(USG)
  105. void exit ();
  106. #endif
  107. #endif
  108. #endif
  109.  
  110. #if defined(LINT_ARGS)
  111. static void date(char *);
  112. static char *center_string(char *, char *);
  113. static void print_tomb(void);
  114. static void kingly(void);
  115. #endif
  116.  
  117. #ifdef ATARIST_TC
  118. /* Include this to get prototypes for standard library functions.  */
  119. #include <stdlib.h>
  120. #endif
  121.  
  122. #ifndef VMS
  123. #ifndef MAC
  124. #if !defined(ATARIST_MWC) && !defined(AMIGA)
  125. long time();
  126. #endif
  127. #endif
  128. #endif
  129.  
  130. static void date(day)
  131. char *day;
  132. {
  133.   register char *tmp;
  134. #ifdef MAC
  135.   time_t clockvar;
  136. #else
  137.   long clockvar;
  138. #endif
  139.  
  140. #ifdef MAC
  141.   clockvar = time((time_t *) 0);
  142. #else
  143.   clockvar = time((long *) 0);
  144. #endif
  145.   tmp = ctime(&clockvar);
  146.   tmp[10] = '\0';
  147.   (void) strcpy(day, tmp);
  148. }
  149.  
  150. /* Centers a string within a 31 character string        -JWT-     */
  151. static char *center_string(centered_str, in_str)
  152. char *centered_str;
  153. char *in_str;
  154. {
  155.   register int i, j;
  156.  
  157.   i = strlen(in_str);
  158.   j = 15 - i/2;
  159.   (void) sprintf (centered_str, "%*s%s%*s", j, "", in_str, 31 - i - j, "");
  160.   return centered_str;
  161. }
  162.  
  163.  
  164. #ifndef __TURBOC__
  165. #if (defined(USG) || defined(atarist)) && !defined(VMS)
  166. #if !defined(AMIGA) && !defined(MAC) && !defined(ATARIST_TC)
  167.  
  168. #include <sys/stat.h>
  169. #include <errno.h>
  170.  
  171. /* The following code is provided especially for systems which        -CJS-
  172.    have no flock system call. It has never been tested.        */
  173.  
  174. #define LOCK_EX    1
  175. #define LOCK_SH    2
  176. #define LOCK_NB    4
  177. #define LOCK_UN    8
  178.  
  179. /* An flock HACK.  LOCK_SH and LOCK_EX are not distinguished.  DO NOT release
  180.    a lock which you failed to set!  ALWAYS release a lock you set! */
  181. static int flock(f, l)
  182. int f, l;
  183. {
  184.   struct stat sbuf;
  185.   char lockname[80];
  186.  
  187.   if (fstat (f, &sbuf) < 0)
  188.     return -1;
  189. #ifdef atarist
  190.   (void) sprintf (lockname, (char *)prefix_file((char *)"moria.%d"),
  191.           sbuf.st_ino);
  192. #else
  193.   (void) sprintf (lockname, "/tmp/moria.%d", sbuf.st_ino);
  194. #endif
  195.   if (l & LOCK_UN)
  196.     return unlink(lockname);
  197.  
  198.   while (open (lockname, O_WRONLY|O_CREAT|O_EXCL, 0644) < 0)
  199.     {
  200.       if (errno != EEXIST)
  201.     return -1;
  202.       if (stat(lockname, &sbuf) < 0)
  203.     return -1;
  204.       /* Locks which last more than 10 seconds get deleted. */
  205.       if (time((long *)0) - sbuf.st_mtime > 10)
  206.     {
  207.       if (unlink(lockname) < 0)
  208.         return -1;
  209.     }
  210.       else if (l & LOCK_NB)
  211.     return -1;
  212.       else
  213.     (void) sleep(1);
  214.     }
  215.   return 0;
  216. }
  217. #endif
  218. #endif
  219. #endif
  220.  
  221. void display_scores(show_player)
  222. int show_player;
  223. {
  224.   register int i, rank;
  225.   high_scores score;
  226.   char input;
  227.   char string[100];
  228.   int8u version_maj, version_min, patch_level;
  229. #if defined(unix) || defined(VMS)
  230.   int16 player_uid;
  231. #endif
  232.  
  233. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  234. #if defined(MAC) || defined(MSDOS)
  235.   if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL)
  236. #else
  237.   if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL)
  238. #endif
  239.     {
  240.       (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP);
  241.       msg_print(string);
  242.       msg_print(CNIL);
  243.       return;
  244.     }
  245. #endif
  246.  
  247. #ifndef BSD4_3
  248.   (void) fseek(highscore_fp, (long)0, L_SET);
  249. #else
  250.   (void) fseek(highscore_fp, (off_t)0, L_SET);
  251. #endif
  252.  
  253.   /* Read version numbers from the score file, and check for validity.  */
  254.   version_maj = getc (highscore_fp);
  255.   version_min = getc (highscore_fp);
  256.   patch_level = getc (highscore_fp);
  257.   /* Support score files from 5.2.2 to present.  */
  258.   if (feof (highscore_fp))
  259.     /* An empty score file. */
  260.     ;
  261.   else if ((version_maj != CUR_VERSION_MAJ)
  262.        || (version_min > CUR_VERSION_MIN)
  263.        || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  264.        || (version_min == 2 && patch_level < 2)
  265.        || (version_min < 2))
  266.     {
  267.       msg_print("Sorry. This scorefile is from a different version of \
  268. umoria.");
  269.       msg_print (CNIL);
  270. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  271.       (void) fclose (highscore_fp);
  272. #endif
  273.       return;
  274.     }
  275.  
  276. #ifdef unix
  277.   player_uid = getuid ();
  278. #else
  279. #ifdef VMS
  280.   player_uid = (getgid()*1000) + getuid();
  281. #else
  282.   /* Otherwise player_uid is not used.  */
  283. #endif
  284. #endif
  285.  
  286.   /* set the static fileptr in save.c to the highscore file pointer */
  287.   set_fileptr(highscore_fp);
  288.  
  289.   rank = 1;
  290.   rd_highscore(&score);
  291.   while (!feof(highscore_fp))
  292.     {
  293.       i = 1;
  294.       clear_screen();
  295.       /* Put twenty scores on each page, on lines 2 through 21. */
  296.       while (!feof(highscore_fp) && i < 21)
  297.     {
  298.       /* Only show the entry if show_player false, or if the entry
  299.          belongs to the current player.  */
  300.       if (! show_player ||
  301. #if defined(unix) || defined(VMS)
  302.           score.uid == player_uid
  303. #else
  304.           /* Assume microcomputers should always show every entry. */
  305.           TRUE
  306. #endif
  307.           )
  308.         {
  309.           (void) sprintf(string,
  310.                "%-4d%8ld %-19.19s %c %-10.10s %-7.7s%3d %-22.22s",
  311.                  rank, score.points, score.name, score.sex,
  312.                  race[score.race].trace, class[score.class].title,
  313.                  score.lev, score.died_from);
  314.           prt(string, ++i, 0);
  315.         }
  316.       rank++;
  317.       rd_highscore(&score);
  318.     }
  319.       prt("Rank  Points Name              Sex Race       Class  Lvl Killed By"
  320.       , 0, 0);
  321.       erase_line (1, 0);
  322.       prt("[Press any key to continue.]", 23, 23);
  323.       input = inkey();
  324.       if (input == ESCAPE)
  325.     break;
  326.     }
  327. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  328.   (void) fclose (highscore_fp);
  329. #endif
  330. }
  331.  
  332.  
  333. int duplicate_character ()
  334. {
  335.   /* Only check for duplicate characters under unix and VMS.  */
  336. #if !defined (unix) && !defined(VMS)
  337.   return FALSE;
  338.  
  339. #else /* ! unix && ! VMS */
  340.  
  341.   high_scores score;
  342.   int8u version_maj, version_min, patch_level;
  343.   int16 player_uid;
  344. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  345.   char string[80];
  346. #endif
  347.  
  348. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  349. #if defined(MAC) || defined(MSDOS)
  350.   if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL)
  351. #else
  352.   if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL)
  353. #endif
  354.     {
  355.       (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP);
  356.       msg_print(string);
  357.       msg_print(CNIL);
  358.       return FALSE;
  359.     }
  360. #endif
  361.  
  362. #ifndef BSD4_3
  363.   (void) fseek(highscore_fp, (long)0, L_SET);
  364. #else
  365.   (void) fseek(highscore_fp, (off_t)0, L_SET);
  366. #endif
  367.  
  368.   /* Read version numbers from the score file, and check for validity.  */
  369.   version_maj = getc (highscore_fp);
  370.   version_min = getc (highscore_fp);
  371.   patch_level = getc (highscore_fp);
  372.   /* Support score files from 5.2.2 to present.  */
  373.   if (feof (highscore_fp))
  374.     /* An empty score file.  */
  375.     return FALSE;
  376.   if ((version_maj != CUR_VERSION_MAJ)
  377.       || (version_min > CUR_VERSION_MIN)
  378.       || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  379.       || (version_min == 2 && patch_level < 2)
  380.       || (version_min < 2))
  381.     {
  382.       msg_print("Sorry. This scorefile is from a different version of \
  383. umoria.");
  384.       msg_print (CNIL);
  385. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  386.       (void) fclose (highscore_fp);
  387. #endif
  388.       return FALSE;
  389.     }
  390.  
  391.   /* set the static fileptr in save.c to the highscore file pointer */
  392.   set_fileptr(highscore_fp);
  393.  
  394. #ifdef unix
  395.   player_uid = getuid ();
  396. #else
  397. #ifdef VMS
  398.   player_uid = (getgid()*1000) + getuid();
  399. #else
  400.   player_uid = 0;
  401. #endif
  402. #endif
  403.  
  404.   rd_highscore(&score);
  405.   while (!feof(highscore_fp))
  406.     {
  407.       if (score.uid == player_uid && score.birth_date == birth_date
  408.       && score.class == py.misc.pclass && score.race == py.misc.prace
  409.       && score.sex == (py.misc.male ? 'M' : 'F')
  410.       && strcmp (score.died_from, "(saved)"))
  411.     return TRUE;
  412.  
  413.       rd_highscore(&score);
  414.     }
  415. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  416.   (void) fclose (highscore_fp);
  417. #endif
  418.  
  419.   return FALSE;
  420. #endif  /* ! unix && ! VMS */
  421. }
  422.  
  423.  
  424.  
  425. /* Prints the gravestone of the character        -RAK-     */
  426. static void print_tomb()
  427. {
  428.   vtype str, tmp_str;
  429.   register int i;
  430.   char day[11];
  431.   register char *p;
  432. #ifdef MAC
  433.   char func;
  434.   int ok;
  435. #endif
  436.  
  437.   clear_screen();
  438.   put_buffer ("_______________________", 1, 15);
  439.   put_buffer ("/", 2, 14);
  440.   put_buffer ("\\         ___", 2, 38);
  441.   put_buffer ("/", 3, 13);
  442.   put_buffer ("\\ ___   /   \\      ___", 3, 39);
  443.   put_buffer ("/            RIP            \\   \\  :   :     /   \\", 4, 12);
  444.   put_buffer ("/", 5, 11);
  445.   put_buffer ("\\  : _;,,,;_    :   :", 5, 41);
  446.   (void) sprintf (str, "/%s\\,;_          _;,,,;_",
  447.           center_string (tmp_str, py.misc.name));
  448.   put_buffer (str, 6, 10);
  449.   put_buffer ("|               the               |   ___", 7, 9);
  450.   if (!total_winner)
  451.     p = title_string ();
  452.   else
  453.     p = "Magnificent";
  454.   (void) sprintf (str, "| %s |  /   \\", center_string (tmp_str, p));
  455.   put_buffer (str, 8, 9);
  456.   put_buffer ("|", 9, 9);
  457.   put_buffer ("|  :   :", 9, 43);
  458.   if (!total_winner)
  459.     p = class[py.misc.pclass].title;
  460.   else if (py.misc.male)
  461.     p = "*King*";
  462.   else
  463.     p = "*Queen*";
  464.   (void) sprintf(str,"| %s | _;,,,;_   ____", center_string (tmp_str, p));
  465.   put_buffer (str, 10, 9);
  466.   (void) sprintf (str, "Level : %d", (int) py.misc.lev);
  467.   (void) sprintf (str,"| %s |          /    \\",
  468.           center_string (tmp_str, str));
  469.   put_buffer (str, 11, 9);
  470.   (void) sprintf(str, "%ld Exp", py.misc.exp);
  471.   (void) sprintf(str,"| %s |          :    :", center_string (tmp_str, str));
  472.   put_buffer (str, 12, 9);
  473.   (void) sprintf(str, "%ld Au", py.misc.au);
  474.   (void) sprintf(str,"| %s |          :    :", center_string (tmp_str, str));
  475.   put_buffer (str, 13, 9);
  476.   (void) sprintf(str, "Died on Level : %d", dun_level);
  477.   (void) sprintf(str,"| %s |         _;,,,,;_", center_string (tmp_str, str));
  478.   put_buffer (str, 14, 9);
  479.   put_buffer ("|            killed by            |", 15, 9);
  480.   p = died_from;
  481.   i = strlen (p);
  482.   p[i] = '.';  /* add a trailing period */
  483.   p[i+1] = '\0';
  484.   (void) sprintf(str, "| %s |", center_string (tmp_str, p));
  485.   put_buffer (str, 16, 9);
  486.   p[i] = '\0';     /* strip off the period */
  487.   date(day);
  488.   (void) sprintf(str, "| %s |", center_string (tmp_str, day));
  489.   put_buffer (str, 17, 9);
  490.   put_buffer ("*|   *     *     *    *   *     *  | *", 18, 8);
  491.   put_buffer ("________)/\\\\_)_/___(\\/___(//_\\)/_\\//__\\\\(/_|_)_______",
  492.           19, 0);
  493.  
  494.  retry:
  495.   flush();
  496. #ifdef MAC
  497.   /* On Mac, file_character() gets file name via std file dialog */
  498.   /* So, the prompt for character record cannot be made to do double duty */
  499.   put_buffer ("('F' - Save record in file / 'Y' - Display record on screen \
  500. / 'N' - Abort)", 23, 0);
  501.   put_buffer ("Character record [F/Y/N]?", 22, 0);
  502.   do
  503.     {
  504.       func = inkey();
  505.       switch (func)
  506.     {
  507.     case 'f': case 'F':
  508.       func = 'F';
  509.       ok = TRUE;
  510.       break;
  511.     case 'y': case 'Y':
  512.       func = 'Y';
  513.       ok = TRUE;
  514.       break;
  515.     case 'n': case 'N':
  516.       func = 'N';
  517.       ok = TRUE;
  518.       break;
  519.     default:
  520.       bell();
  521.       ok = FALSE;
  522.       break;
  523.     }
  524.     }
  525.   while (!ok);
  526.   if (func != 'N')
  527. #else
  528.   put_buffer ("(ESC to abort, return to print on screen, or file name)",
  529.           23, 0);
  530.   put_buffer ("Character record?", 22, 0);
  531.   if (get_string (str, 22, 18, 60))
  532. #endif
  533.     {
  534.       for (i = 0; i < INVEN_ARRAY_SIZE; i++)
  535.     {
  536.       known1(&inventory[i]);
  537.       known2(&inventory[i]);
  538.     }
  539.       calc_bonuses ();
  540. #ifdef MAC
  541.       if (func == 'F')
  542.     {
  543.       if (!file_character())
  544.         goto retry;
  545.     }
  546. #else
  547.       if (str[0])
  548.     {
  549.       if (!file_character (str))
  550.         goto retry;
  551.     }
  552. #endif
  553.       else
  554.     {
  555.       clear_screen ();
  556.       display_char ();
  557.       put_buffer ("Type ESC to skip the inventory:", 23, 0);
  558.       if (inkey() != ESCAPE)
  559.         {
  560.           clear_screen ();
  561.           msg_print ("You are using:");
  562.           (void) show_equip (TRUE, 0);
  563.           msg_print (CNIL);
  564.           msg_print ("You are carrying:");
  565.           clear_from (1);
  566.           (void) show_inven (0, inven_ctr-1, TRUE, 0, CNIL);
  567.           msg_print (CNIL);
  568.         }
  569.     }
  570.     }
  571. }
  572.  
  573.  
  574. /* Calculates the total number of points earned        -JWT-     */
  575. int32 total_points()
  576. {
  577.   int32 total;
  578.   int i;
  579.  
  580.   total = py.misc.max_exp + (100 * py.misc.max_dlv);
  581.   total += py.misc.au / 100;
  582.   for (i = 0; i < INVEN_ARRAY_SIZE; i++)
  583.     total += item_value(&inventory[i]);
  584.   total += dun_level*50;
  585.  
  586.   /* Don't ever let the score decrease from one save to the next.  */
  587.   if (max_score > total)
  588.     return max_score;
  589.  
  590.   return total;
  591. }
  592.  
  593.  
  594. /* Enters a players name on the top twenty list        -JWT-     */
  595. static void highscores()
  596. {
  597.   high_scores old_entry, new_entry, entry;
  598.   int i;
  599.   char *tmp;
  600.   int8u version_maj, version_min, patch_level;
  601.   long curpos;
  602. #if defined(VMS) || defined(MSDOS) || defined(AMIGA) || defined(MAC)
  603.   char string[100];
  604. #endif
  605.  
  606.   clear_screen();
  607.  
  608.   if (noscore)
  609.     return;
  610.  
  611.   if (panic_save == 1)
  612.     {
  613.       msg_print("Sorry, scores for games restored from panic save files \
  614. are not saved.");
  615.       return;
  616.     }
  617.  
  618.   new_entry.points = total_points();
  619.   new_entry.birth_date = birth_date;
  620. #ifdef unix
  621.   new_entry.uid = getuid();
  622. #else
  623. #ifdef VMS
  624.   new_entry.uid = (getgid()*1000) + getuid();
  625. #else
  626.   new_entry.uid = 0;
  627. #endif
  628. #endif
  629.   new_entry.mhp = py.misc.mhp;
  630.   new_entry.chp = py.misc.chp;
  631.   new_entry.dun_level = dun_level;
  632.   new_entry.lev = py.misc.lev;
  633.   new_entry.max_dlv = py.misc.max_dlv;
  634.   new_entry.sex = (py.misc.male ? 'M' : 'F');
  635.   new_entry.race = py.misc.prace;
  636.   new_entry.class = py.misc.pclass;
  637.   (void) strcpy(new_entry.name, py.misc.name);
  638.   tmp = died_from;
  639.   if ('a' == *tmp)
  640.     {
  641.       if ('n' == *(++tmp))
  642.     {
  643.       tmp++;
  644.     }
  645.       while (isspace(*tmp))
  646.     {
  647.       tmp++;
  648.     }
  649.     }
  650.   (void) strcpy(new_entry.died_from, tmp);
  651.  
  652.   /*  First, get a lock on the high score file so no-one else tries */
  653.   /*  to write to it while we are using it, on VMS and IBMPCs only one
  654.       process can have the file open at a time, so we just open it here */
  655. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  656. #if defined(MAC) || defined(MSDOS)
  657.   if ((highscore_fp = fopen(MORIA_TOP, "rb+")) == NULL)
  658. #else
  659.   if ((highscore_fp = fopen(MORIA_TOP, "r+")) == NULL)
  660. #endif
  661.     {
  662.       (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP);
  663.       msg_print(string);
  664.       msg_print(CNIL);
  665.       return;
  666.     }
  667. #else
  668. #ifdef ATARIST_TC
  669.   /* 'lock' always succeeds on the Atari ST */
  670. #else
  671.   if (0 != flock((int)fileno(highscore_fp), LOCK_EX))
  672.     {
  673.       msg_print("Error gaining lock for score file");
  674.       msg_print(CNIL);
  675.       return;
  676.     }
  677. #endif
  678. #endif
  679.  
  680.   /* Search file to find where to insert this character, if uid != 0 and
  681.      find same uid/sex/race/class combo then exit without saving this score */
  682.   /* Seek to the beginning of the file just to be safe. */
  683. #ifndef BSD4_3
  684.   (void) fseek(highscore_fp, (long)0, L_SET);
  685. #else
  686.   (void) fseek(highscore_fp, (off_t)0, L_SET);
  687. #endif
  688.  
  689.   /* Read version numbers from the score file, and check for validity.  */
  690.   version_maj = getc (highscore_fp);
  691.   version_min = getc (highscore_fp);
  692.   patch_level = getc (highscore_fp);
  693.   /* If this is a new scorefile, it should be empty.  Write the current
  694.      version numbers to the score file.  */
  695.   if (feof (highscore_fp))
  696.     {
  697.       /* Seek to the beginning of the file just to be safe. */
  698. #ifndef BSD4_3
  699.       (void) fseek(highscore_fp, (long)0, L_SET);
  700. #else
  701.       (void) fseek(highscore_fp, (off_t)0, L_SET);
  702. #endif
  703.  
  704.       (void) putc (CUR_VERSION_MAJ, highscore_fp);
  705.       (void) putc (CUR_VERSION_MIN, highscore_fp);
  706.       (void) putc (PATCH_LEVEL, highscore_fp);
  707.  
  708.       /* must fseek() before can change read/write mode */
  709. #ifndef BSD4_3
  710. #ifdef ATARIST_TC
  711.       /* no fseek relative to current position allowed */
  712.       (void) fseek (highscore_fp, (long)ftell (highscore_fp), L_SET);
  713. #else
  714.       (void) fseek(highscore_fp, (long)0, L_INCR);
  715. #endif
  716. #else
  717.       (void) fseek(highscore_fp, (off_t)0, L_INCR);
  718. #endif
  719.     }
  720.   /* Support score files from 5.2.2 to present.  */
  721.   else if ((version_maj != CUR_VERSION_MAJ)
  722.        || (version_min > CUR_VERSION_MIN)
  723.        || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  724.        || (version_min == 2 && patch_level < 2)
  725.        || (version_min < 2))
  726.     {
  727.       /* No need to print a message, a subsequent call to display_scores()
  728.      will print a message.  */
  729. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  730.       (void) fclose (highscore_fp);
  731. #endif
  732.       return;
  733.     }
  734.  
  735.   /* set the static fileptr in save.c to the highscore file pointer */
  736.   set_fileptr(highscore_fp);
  737.  
  738.   i = 0;
  739.   curpos = ftell (highscore_fp);
  740.   rd_highscore(&old_entry);
  741.   while (!feof(highscore_fp))
  742.     {
  743.       if (new_entry.points >= old_entry.points)
  744.     break;
  745.       /* under unix and VMS, only allow one sex/race/class combo per person,
  746.      on single user system, allow any number of entries, but try to
  747.      prevent multiple entries per character by checking for case when
  748.      birthdate/sex/race/class are the same, and died_from of scorefile
  749.      entry is "(saved)" */
  750.       else if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid)
  751.         || (new_entry.uid == 0 &&!strcmp(old_entry.died_from,"(saved)")
  752.             && new_entry.birth_date == old_entry.birth_date))
  753.            && new_entry.sex == old_entry.sex
  754.            && new_entry.race == old_entry.race
  755.            && new_entry.class == old_entry.class)
  756.     {
  757. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  758.       (void) fclose (highscore_fp);
  759. #endif
  760.       return;
  761.     }
  762.       else if (++i >= SCOREFILE_SIZE)
  763.     {
  764.       /* only allow one thousand scores in the score file */
  765. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  766.       (void) fclose (highscore_fp);
  767. #endif
  768.       return;
  769.     }
  770.       curpos = ftell (highscore_fp);
  771.       rd_highscore(&old_entry);
  772.     }
  773.  
  774.   if (feof(highscore_fp))
  775.     {
  776.       /* write out new_entry at end of file */
  777. #ifndef BSD4_3
  778.       (void) fseek (highscore_fp, curpos, L_SET);
  779. #else
  780.       (void) fseek (highscore_fp, (off_t)curpos, L_SET);
  781. #endif
  782.       wr_highscore(&new_entry);
  783.     }
  784.   else
  785.     {
  786.       entry = new_entry;
  787.       while (!feof(highscore_fp))
  788.     {
  789. #ifndef BSD4_3
  790. #ifdef ATARIST_TC || defined(__TURBOC__)
  791.       /* No fseek with negative offset allowed.  */
  792.       (void) fseek(highscore_fp, (long)ftell(highscore_fp) -
  793.                sizeof(high_scores) - sizeof (char), L_SET);
  794. #else
  795.       (void) fseek(highscore_fp,
  796.                -(long)sizeof(high_scores)-(long)sizeof(char),
  797.                L_INCR);
  798. #endif
  799. #else
  800.       (void) fseek(highscore_fp,
  801.                -(off_t)sizeof(high_scores)-(off_t)sizeof(char),
  802.                L_INCR);
  803. #endif
  804.       wr_highscore(&entry);
  805.       /* under unix and VMS, only allow one sex/race/class combo per
  806.          person, on single user system, allow any number of entries, but
  807.          try to prevent multiple entries per character by checking for
  808.          case when birthdate/sex/race/class are the same, and died_from of
  809.          scorefile entry is "(saved)" */
  810.       if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid)
  811.         || (new_entry.uid == 0 &&!strcmp(old_entry.died_from,"(saved)")
  812.             && new_entry.birth_date == old_entry.birth_date))
  813.           && new_entry.sex == old_entry.sex
  814.           && new_entry.race == old_entry.race
  815.           && new_entry.class == old_entry.class)
  816.         break;
  817.       entry = old_entry;
  818.       /* must fseek() before can change read/write mode */
  819. #ifndef BSD4_3
  820. #ifdef ATARIST_TC
  821.       /* No fseek relative to current position allowed.  */
  822.       (void) fseek(highscore_fp, (long)ftell(highscore_fp), L_SET);
  823. #else
  824.       (void) fseek(highscore_fp, (long)0, L_INCR);
  825. #endif
  826. #else
  827.       (void) fseek(highscore_fp, (off_t)0, L_INCR);
  828. #endif
  829.       curpos = ftell (highscore_fp);
  830.       rd_highscore(&old_entry);
  831.     }
  832.       if (feof(highscore_fp))
  833.     {
  834. #ifndef BSD4_3
  835.       (void) fseek (highscore_fp, curpos, L_SET);
  836. #else
  837.       (void) fseek (highscore_fp, (off_t)curpos, L_SET);
  838. #endif
  839.       wr_highscore(&entry);
  840.     }
  841.     }
  842.  
  843. #if !defined(VMS) && !defined(MSDOS) && !defined(AMIGA) && !defined(MAC)
  844. #ifdef ATARIST_TC
  845.   /* Flock never called for Atari ST with TC.  */
  846. #else
  847.   (void) flock((int)fileno(highscore_fp), LOCK_UN);
  848. #endif
  849. #else
  850.   (void) fclose (highscore_fp);
  851. #endif
  852. }
  853.  
  854.  
  855. /* Change the player into a King!            -RAK-     */
  856. static void kingly()
  857. {
  858.   register struct misc *p_ptr;
  859.   register char *p;
  860.  
  861.   /* Change the character attributes.         */
  862.   dun_level = 0;
  863.   (void) strcpy(died_from, "Ripe Old Age");
  864.   p_ptr = &py.misc;
  865.   (void) restore_level ();
  866.   p_ptr->lev += MAX_PLAYER_LEVEL;
  867.   p_ptr->au += 250000L;
  868.   p_ptr->max_exp += 5000000L;
  869.   p_ptr->exp = p_ptr->max_exp;
  870.  
  871.   /* Let the player know that he did good.     */
  872.   clear_screen();
  873.   put_buffer("#", 1, 34);
  874.   put_buffer("#####", 2, 32);
  875.   put_buffer("#", 3, 34);
  876.   put_buffer(",,,  $$$  ,,,", 4, 28);
  877.   put_buffer(",,=$   \"$$$$$\"   $=,,", 5, 24);
  878.   put_buffer(",$$        $$$        $$,", 6, 22);
  879.   put_buffer("*>         <*>         <*", 7, 22);
  880.   put_buffer("$$         $$$         $$", 8, 22);
  881.   put_buffer("\"$$        $$$        $$\"", 9, 22);
  882.   put_buffer("\"$$       $$$       $$\"", 10, 23);
  883.   p = "*#########*#########*";
  884.   put_buffer(p, 11, 24);
  885.   put_buffer(p, 12, 24);
  886.   put_buffer("Veni, Vidi, Vici!", 15, 26);
  887.   put_buffer("I came, I saw, I conquered!", 16, 21);
  888.   if (p_ptr->male)
  889.     put_buffer("All Hail the Mighty King!", 17, 22);
  890.   else
  891.     put_buffer("All Hail the Mighty Queen!", 17, 22);
  892.   flush();
  893.   pause_line(23);
  894. }
  895.  
  896.  
  897. /* Handles the gravestone end top-twenty routines    -RAK-     */
  898. void exit_game ()
  899. {
  900. #ifdef MAC
  901.   /* Prevent strange things from happening */
  902.   enablefilemenu(FALSE);
  903. #endif
  904.  
  905.   /* What happens upon dying.                -RAK-     */
  906.   msg_print(CNIL);
  907.   flush ();  /* flush all input */
  908.   nosignals ();     /* Can't interrupt or suspend. */
  909.   /* If the game has been saved, then save sets turn back to -1, which
  910.      inhibits the printing of the tomb.     */
  911.   if (turn >= 0)
  912.     {
  913.       if (total_winner)
  914.     kingly();
  915.       print_tomb();
  916.     }
  917.   if (character_generated && !character_saved)
  918. #ifdef MAC
  919.     (void) save_char (TRUE);        /* Save the memory at least. */
  920. #else
  921.     (void) save_char ();        /* Save the memory at least. */
  922. #endif
  923.   /* add score to scorefile if applicable */
  924.   if (character_generated)
  925.     {
  926.       /* Clear character_saved, strange thing to do, but it prevents inkey()
  927.      from recursively calling exit_game() when there has been an eof
  928.      on stdin detected.  */
  929.       character_saved = FALSE;
  930.       highscores();
  931.       display_scores (TRUE);
  932.     }
  933.   erase_line (23, 0);
  934.   restore_term ();
  935. #ifdef MAC
  936.   /* Undo what has been done */
  937.   enablefilemenu(TRUE);
  938.   /* Long jump back into the Mac wrapper, in lieu of exit () */
  939.   goback();
  940. #else
  941.   exit (0);
  942. #endif
  943. }
  944.